package spring.beans.factory;

import spring.BeansException;
import spring.annotation.Autowired;
import spring.beans.BeanFactoryAware;
import spring.beans.BeanNameAware;
import spring.beans.BeanPostProcessor;
import spring.beans.InitializingBean;
import spring.beans.config.BeanDefinition;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry {

    /**
     * 存储BeanDefinition对象， 实现BeanDefinitionRegistry接口
     */
    private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

    /**
     * 存储BeanPostProcessor
     */
    private List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();

    /***
     * 被代理对象
     */
    public HashSet<String> exposedObjectSet = new HashSet<>();



    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
        beanDefinitionMap.put(beanName, beanDefinition);
    }

    @Override
    public BeanDefinition getBeanDefinition(String beanName) {
        return beanDefinitionMap.get(beanName);
    }

    @Override
    public boolean containsBeanDefinition(String beanName) {
        return beanDefinitionMap.containsKey(beanName);
    }

    @Override
    public void removeBeanDefinition(String beanName) {
        beanDefinitionMap.remove(beanName);
    }

    @Override
    public String[] getBeanDefinitionNames() {
        String[] arr = new String[beanDefinitionMap.size()];
        int index = 0;
        for (String beanDefinitionName : beanDefinitionMap.keySet()) {
            arr[index++] = beanDefinitionName;
        }
        return arr;
    }

    @Override
    public Class<?> getType(String beanName) {
        return getBeanDefinition(beanName).getClazz();
    }

    @Override
    protected Object doGetBean(String beanName) {
        // 先获得bean定义对象
        if (containsBeanDefinition(beanName)) {
            BeanDefinition beanDefinition = getBeanDefinition(beanName);
            // 是单例还是原型
            if (beanDefinition.isSingleton()) {
                Object bean;
                bean = getSingleton(beanName);
                // 没有就创建，返回，放到池子里
                if (bean == null) {
                    bean = createBean(beanName,beanDefinition);
                    registerSingleton(beanName,bean);
                }
                return bean;
            } else if (beanDefinition.isPrototype()) {
                // 创建bean对象
                return createBean(beanName, beanDefinition);
            } else {
                throw new BeansException("未知scope");
            }
        }
        return null;
    }


    /**
     * 注册非懒加载单例
     */
    public void preInstantiateSingletons(){
        for(String beanName: beanDefinitionMap.keySet()) {
            BeanDefinition beanDefinition = getBeanDefinition(beanName);
            if (beanDefinition.isSingleton()) {
                Object bean = createBean(beanName,beanDefinition);
                System.out.println("注册单例："+beanName);
                registerSingleton(beanName, bean);
            }
        }
    }

    /**
     * 返回实现该类的bean定义
     * @param objClass
     * @return
     */
    public ArrayList<String> getBeanNamesForType(Class objClass) {
        ArrayList<String> list = new ArrayList<>();
        for (String key : beanDefinitionMap.keySet()) {
            BeanDefinition value = beanDefinitionMap.get(key);
            if (objClass.isAssignableFrom(value.getClazz())) {
                list.add(key);
            }
        }
        return list;
    }


    public void addBeanPostProcessor(BeanPostProcessor postProcessor) {
        beanPostProcessors.add(postProcessor);
    }
    public List<BeanPostProcessor> getBeanPostProcessors(){
        return beanPostProcessors;
    }

    @Override
    protected Object applyBeanPostProcessorsAfterInitialization(String beanName, Object instance) {
        Object AfterPostBean = instance;
        for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {
            AfterPostBean = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);
        }
        return AfterPostBean;
    }

    @Override
    protected void invokeAwareMethods(String beanName, Object instance) {
        if (instance instanceof BeanNameAware) {
            ((BeanNameAware) instance).setBeanName(beanName);
        }
        if (instance instanceof BeanFactoryAware) {
            ((BeanFactoryAware) instance).setBeanFactory(this);
        }
    }

    @Override
    protected Object applyBeanPostProcessorsBeforeInitialization(String beanName, Object instance) throws Exception {
        Object AfterPostBean = instance;
        for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {
            AfterPostBean = beanPostProcessor.postProcessAfterInitialization(instance, beanName);
        }
        return AfterPostBean;
    }
}
